package gr.aueb.cs.mscis.chordroid.chord;

import gr.aueb.cs.mscis.chordroid.ChordroidService;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;

import android.util.Log;

/**
 * RemoteMessageDaemon stands as the main entity for remote method requests.
 * It is basically a ServerSocket that accepts and handles {@code RemoteMessage}s 
 * @author lupin
 */
public class RemoteMessageDaemon implements Runnable,Serializable {

	private static final long serialVersionUID = 1L;
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	private ServerSocket welcomeSocket;
	private Socket inFromClient;
	private int port;
	private Node node;
		
	public RemoteMessageDaemon(){}
	
	public RemoteMessageDaemon(int listeningPort) {
		this.port = listeningPort;

	}

	public void run() {
		listen();
	}


	public void listen() {
		try {
			welcomeSocket = new ServerSocket(port);
			for (;;) {
				inFromClient = welcomeSocket.accept();
				ois = new ObjectInputStream(inFromClient.getInputStream());
				RemoteMessage message = (RemoteMessage) ois.readObject();
				
				// respond to synchronous calls
				if ((message.getProtocolType().equals(ProtocolType.GET_SUCCESSOR_LIST))){
					oos = new ObjectOutputStream(inFromClient.getOutputStream());
					RemoteMessage rm = new RemoteMessage(ProtocolType.GET_SUCCESSOR_LIST_REPLY,
							ChordroidService.getMyLuckyNode().getSuccessorList(),null);
					oos.writeObject(rm);
					oos.close();
				} else	if (message.getProtocolType().equals(ProtocolType.GET_PREDECESSOR)) {
					oos = new ObjectOutputStream(inFromClient.getOutputStream());
					RemoteMessage rm = new RemoteMessage(ProtocolType.GET_PREDECESSOR_REPLY,
							ChordroidService.getMyLuckyNode().getPredecessor(),null);
					oos.writeObject(rm);
					oos.close();
				} else {
					respondToRemoteMessage(message);
				}
				if (inFromClient != null) inFromClient.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Handles the RemoteMessage based on its ProtocolType
	 * @param msg
	 */
	private synchronized void respondToRemoteMessage(RemoteMessage msg) {
		
		if (msg.getProtocolType().equals(ProtocolType.CREATE_CHORD)) {
			ChordroidService.getMyLuckyNode().create();
			return;
		} else if (msg.getProtocolType().equals(ProtocolType.NOTIFY))
			ChordroidService.getMyLuckyNode().notify(msg.getNodeId());
		else if (msg.getProtocolType().equals(ProtocolType.FIND_SUCCESSOR))
			ChordroidService.getMyLuckyNode()
			.findSuccessor(msg.getPayload().toString(), msg.getNodeId());
		else if (msg.getProtocolType().equals(ProtocolType.FIND_SUCCESSOR_RESULT))
			ChordroidService.getMyLuckyNode().setSuccessor((NodeIdentifier) msg.getPayload());
		else if (msg.getProtocolType().equals(ProtocolType.FIND_SUCCESSOR_RESULT_FOR_APP))
			ChordroidService.getApp().getHashMap().put(
					(String) msg.getPayload(), // add the hash which started the find successor
					msg.getNodeId()); // add the string of the addr + port of the succ
		else if (msg.getProtocolType().equals(ProtocolType.LEAVE_CHORD)) {
			//den xrhsimopoioume else if gia thn periptwsh pou successor kai predeccessor einai idioi
			if (msg.getNodeId().toString().equals(ChordroidService.getMyLuckyNode().getSuccessor().toString()))
				ChordroidService.getMyLuckyNode().setSuccessor((NodeIdentifier) msg.getPayload());
			if (msg.getNodeId().toString().equals(ChordroidService.getMyLuckyNode().getPredecessor().toString()))
				ChordroidService.getMyLuckyNode().setPredecessor((NodeIdentifier) msg.getPayload());
			Log.v("surviror","pussy left chord" + msg.getNodeId());
		}	
	}

	public void setNode(Node node) {
		this.node = node;
	}

	public Node getNode() {
		return node;
	}

}